"""
验证器工具类
用于邮箱验证码生成、发送和验证
实现系统级别的全局锁定/解锁机制，管理员验证后所有用户均可访问
"""
import os
import json
import random
import string
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from datetime import datetime, timedelta


class AuthVerifier:
    """认证验证器"""
    
    def __init__(self, app=None):
        """初始化验证器"""
        self.app = app
        if app is not None:
            self.init_app(app)
    
    def init_app(self, app):
        """初始化应用配置"""
        self.app = app
        self.admin_email = app.config.get('ADMIN_EMAIL')
        self.validity_days = app.config.get('VERIFICATION_VALIDITY_DAYS', 30)
        self.auth_data_file = app.config.get('AUTH_DATA_FILE')
    
    def generate_code(self, length=6):
        """
        生成随机验证码
        :param length: 验证码长度
        :return: 验证码字符串
        """
        return ''.join(random.choices(string.digits, k=length))
    
    def send_verification_email(self, email, code):
        """
        发送验证码邮件 - 使用smtplib直接发送
        :param email: 收件人邮箱
        :param code: 验证码
        :return: 成功返回True，失败返回False
        """
        try:
            # 获取邮件配置
            mail_server = self.app.config.get('MAIL_SERVER')
            mail_port = self.app.config.get('MAIL_PORT')
            mail_username = self.app.config.get('MAIL_USERNAME')
            mail_password = self.app.config.get('MAIL_PASSWORD')
            mail_use_tls = self.app.config.get('MAIL_USE_TLS', True)
            
            if not all([mail_server, mail_port, mail_username, mail_password]):
                print("邮件配置不完整")
                return False
            
            # 创建邮件
            message = MIMEMultipart('alternative')
            message['From'] = mail_username
            message['To'] = email
            message['Subject'] = 'JYB工具箱 - 系统验证码'
            
            # 纯文本版本
            text_content = f"""
JYB工具箱 - 系统验证

您好！

您的系统解锁验证码是：

    {code}

验证码有效期为 10 分钟，请及时使用。

如果这不是您本人的操作，请忽略此邮件。

---
此邮件由系统自动发送，请勿回复。
JYB工具箱
"""
            
            # HTML版本
            html_content = f"""
<html>
<body style="font-family: 'Microsoft YaHei', Arial, sans-serif; line-height: 1.6; color: #333;">
    <div style="max-width: 600px; margin: 0 auto; padding: 20px; background-color: #f9f9f9;">
        <div style="background-color: white; padding: 30px; border-radius: 10px; box-shadow: 0 2px 5px rgba(0,0,0,0.1);">
            <h2 style="color: #007bff; border-bottom: 3px solid #007bff; padding-bottom: 10px; margin-bottom: 20px;">
                JYB工具箱 - 系统验证
            </h2>
            
            <p style="font-size: 16px; margin-bottom: 20px;">
                您好！
            </p>
            
            <p style="font-size: 16px; margin-bottom: 20px;">
                您的系统解锁验证码是：
            </p>
            
            <div style="background-color: #f0f8ff; border: 2px solid #007bff; border-radius: 8px; padding: 20px; text-align: center; margin: 30px 0;">
                <span style="font-size: 36px; font-weight: bold; color: #007bff; letter-spacing: 8px;">
                    {code}
                </span>
            </div>
            
            <p style="font-size: 14px; color: #666; margin-top: 20px;">
                <strong>重要提示：</strong>验证码有效期为 <strong>10 分钟</strong>，请及时使用。
            </p>
            
            <hr style="border: none; border-top: 1px solid #ddd; margin: 30px 0;">
            
            <p style="font-size: 12px; color: #999;">
                如果这不是您本人的操作，请忽略此邮件。<br>
                此邮件由系统自动发送，请勿回复。
            </p>
            
            <p style="font-size: 12px; color: #999; margin-top: 20px;">
                <strong>JYB工具箱</strong>
            </p>
        </div>
    </div>
</body>
</html>
"""
            
            # 添加文本和HTML部分（明确指定UTF-8编码）
            part1 = MIMEText(text_content, 'plain', 'utf-8')
            part2 = MIMEText(html_content, 'html', 'utf-8')
            message.attach(part1)
            message.attach(part2)
            
            # 发送邮件
            print(f"正在连接到 {mail_server}:{mail_port}...")
            
            if mail_use_tls:
                # 使用TLS (STARTTLS)
                server = smtplib.SMTP(mail_server, mail_port, timeout=10)
                server.ehlo()
                server.starttls()
                server.ehlo()
            else:
                # 直接连接或使用SSL
                if mail_port == 465:
                    server = smtplib.SMTP_SSL(mail_server, mail_port, timeout=10)
                else:
                    server = smtplib.SMTP(mail_server, mail_port, timeout=10)
            
            print(f"正在登录 {mail_username}...")
            server.login(mail_username, mail_password)
            
            print(f"正在发送邮件到 {email}...")
            server.sendmail(mail_username, email, message.as_string())
            server.quit()
            
            print("邮件发送成功！")
            return True
            
        except smtplib.SMTPAuthenticationError as e:
            print(f"SMTP认证错误: {e}")
            print("请检查邮箱用户名和密码/授权码")
            return False
        except smtplib.SMTPException as e:
            print(f"SMTP错误: {e}")
            import traceback
            traceback.print_exc()
            return False
        except Exception as e:
            print(f"邮件发送失败: {e}")
            import traceback
            traceback.print_exc()
            return False
    
    def save_verification_code(self, code):
        """
        保存验证码到本地文件
        :param code: 验证码
        """
        now = datetime.now()
        data = {
            'code': code,
            'timestamp': now.isoformat(),
            'expires_at': (now + timedelta(minutes=10)).isoformat()
        }
        
        with open(self.auth_data_file, 'w', encoding='utf-8') as f:
            json.dump(data, f, ensure_ascii=False, indent=2)
    
    def verify_code(self, input_code):
        """
        验证用户输入的验证码
        :param input_code: 用户输入的验证码
        :return: 返回字典 {'success': bool, 'message': str}
        """
        if not os.path.exists(self.auth_data_file):
            return {'success': False, 'message': '验证码不存在，请先发送验证码'}
        
        try:
            with open(self.auth_data_file, 'r', encoding='utf-8') as f:
                data = json.load(f)
            
            # 检查是否存在验证码（如果已验证成功，文件中没有code字段）
            if 'code' not in data:
                return {'success': False, 'message': '请先发送验证码'}
            
            # 检查验证码是否过期
            expires_at = datetime.fromisoformat(data['expires_at'])
            now = datetime.now()
            
            if now > expires_at:
                return {'success': False, 'message': '验证码已过期，请重新发送'}
            
            # 验证验证码
            if data['code'] == input_code:
                return {'success': True, 'message': '验证成功'}
            else:
                return {'success': False, 'message': '验证码错误，请检查后重新输入'}
                
        except KeyError as e:
            print(f"验证码数据格式错误: {e}")
            return {'success': False, 'message': '验证数据格式错误，请重新发送验证码'}
        except Exception as e:
            print(f"验证码验证失败: {e}")
            import traceback
            traceback.print_exc()
            return {'success': False, 'message': f'验证失败: {str(e)}'}
    
    def save_verification_success(self):
        """
        保存验证成功记录（全局解锁系统）
        验证成功后，所有用户都可以访问系统
        """
        now = datetime.now()
        data = {
            'verified_at': now.isoformat(),
            'expires_at': (now + timedelta(days=self.validity_days)).isoformat()
        }
        
        with open(self.auth_data_file, 'w', encoding='utf-8') as f:
            json.dump(data, f, ensure_ascii=False, indent=2)
    
    def check_verification_status(self):
        """
        检查系统全局验证状态（而非单个用户）
        :return: 返回字典 {'valid': bool, 'message': str, 'expires_at': str}
        valid=True 表示系统已解锁，所有用户都可以访问
        """
        if not os.path.exists(self.auth_data_file):
            return {
                'valid': False,
                'message': '系统首次启动，需要验证',
                'expires_at': None
            }
        
        try:
            with open(self.auth_data_file, 'r', encoding='utf-8') as f:
                data = json.load(f)
            
            # 如果有code字段，说明是待验证状态
            if 'code' in data:
                return {
                    'valid': False,
                    'message': '等待验证码验证',
                    'expires_at': None
                }
            
            # 检查验证是否过期
            expires_at = datetime.fromisoformat(data['expires_at'])
            if datetime.now() > expires_at:
                return {
                    'valid': False,
                    'message': f'验证已过期（超过{self.validity_days}天），需要重新验证',
                    'expires_at': data['expires_at']
                }
            
            # 验证有效
            remaining_days = (expires_at - datetime.now()).days
            return {
                'valid': True,
                'message': f'验证有效，剩余 {remaining_days} 天',
                'expires_at': data['expires_at']
            }
        except Exception as e:
            print(f"检查验证状态失败: {e}")
            return {
                'valid': False,
                'message': '验证数据异常，需要重新验证',
                'expires_at': None
            }
    
    def get_admin_email(self):
        """获取管理员邮箱"""
        return self.admin_email
    
    def is_email_configured(self):
        """检查邮件配置是否完整"""
        return bool(self.app.config.get('MAIL_USERNAME') and 
                   self.app.config.get('MAIL_PASSWORD') and 
                   self.admin_email)

